import React, { FormEventHandler, PropsWithChildren, useState } from 'react'
import Layout from '@theme/Layout'
import { HttpMethodsEnum } from 'konfig-lib/dist/forEachOperation'
import moment from 'moment'
import clsx from 'clsx'
import Head from '@docusaurus/Head'
import {
  IconAdjustments,
  IconApi,
  IconChevronDown,
  IconCodeDots,
  IconCube,
  IconInfoCircle,
  IconLink,
  IconPencil,
  IconPlayerPlay,
  TablerIconsProps,
} from '@tabler/icons-react'
import { Markdown } from './Markdown'
import type {
  SdkPageProps,
  Parameter,
  Method,
  HttpMethods,
} from './SdkComponentProps'
import { TsIcon } from './TsIcon'
import { useSdkSignup } from '../util/use-sdk-signup'
import { LoadingIcon } from './LoadingIcon'

type ReactProps = {
  GettingStarted: React.ComponentType
  Description: React.ComponentType
  FirstRequest?: React.ComponentType
  language?: string
  doesNotHaveApiDescription?: boolean
  categories?: string[]
  companyKebabCase: string
}

export function Sdk({
  metaDescription,
  company,
  logo,
  homepage,
  lastUpdated,
  methods,
  serviceName,
  apiTitle,
  apiBaseUrl,
  apiVersion,
  endpoints,
  sdkMethods,
  schemas,
  parameters,
  difficulty,
  contactUrl,
  contactEmail,
  openApiRaw,
  previewLinkImage,
  sdkName,
  clientNameCamelCase,
  faviconUrl,
  GettingStarted,
  Description,
  language = 'TypeScript',
  doesNotHaveApiDescription,
}: Omit<SdkPageProps, 'difficultyScore' | 'providerName'> & ReactProps) {
  const serviceNameSubstring =
    serviceName !== undefined ? ` ${serviceName}` : ''
  const description = `Explore the ${company}${serviceNameSubstring} TypeScript SDK. Dive into comprehensive documentation and utilize ${methods.length} methods to integrate ${company}'s${serviceNameSubstring} API into your application.`
  const homepageWithHttpScheme =
    homepage.startsWith('https://') || homepage.startsWith('http://')
      ? homepage
      : `https://${homepage}`
  return (
    <Layout
      title={`${company}${serviceNameSubstring} API - ${language} SDK, Documentation, and OpenAPI Specification`}
      description={description}
    >
      <Head>
        {/* <link
          rel="icon"
          href={
            faviconUrl
              ? faviconUrl
              : `http://www.google.com/s2/favicons?domain=${homepage}&sz=128`
          }
        /> */}
        <meta property="og:image" content={previewLinkImage} />
        <meta property="og:description" content={description} />
        <style>
          {`p {
            margin-bottom: 0px;
          }`}
        </style>
      </Head>
      <div className="bg-slate-100 border-b">
        <div className="py-8 bg-gradient-to-tl from-[var(--ifm-color-primary-darkest)] to-[var(--ifm-color-primary)]">
          <BigSection>
            <div className="p-8 w-fit bg-gradient-to-t ring-1 ring-slate-200 from-white to-slate-100 relative top-20 bg-white rounded-md shadow-xl">
              <img className="h-6 mb-4" src={logo} alt={`${company} Logo`} />
              <h1 className="flex gap-2 text-2xl lg:text-3xl mb-2">
                <span>{sdkName}</span>
                <TsIcon className="h-5 w-5" />
              </h1>
              <div className="flex flex-wrap gap-x-3 gap-y-1 items-center text-xs sm:text-sm md:text-base">
                {apiVersion && (
                  <>
                    <div className="font-mono text-slate-500">{apiVersion}</div>
                    {apiVersion && <Dot />}
                  </>
                )}
                <div className="font-mono">
                  <a href="https://konfigthis.com" target="_blank">
                    SDK Generated by Konfig
                  </a>
                </div>
                <Dot />
                <div className="font-mono">
                  <a href={homepageWithHttpScheme} target="_blank">
                    {homepage}
                  </a>
                </div>
                <Dot />
                <div className="font-mono text-slate-500">
                  Updated {moment(lastUpdated).format('MMMM Do, YYYY')}
                </div>
              </div>
            </div>
          </BigSection>
        </div>
        <BigSection>
          <div className="flex flex-col pt-24 pb-10 lg:flex-row lg:gap-10 items-start justify-between">
            <div className="grow w-full lg:max-w-xl xl:max-w-3xl">
              <SignupForm
                company={company}
                serviceName={serviceName}
                language={language}
              />
              <div className="text-slate-500 mb-1 text-sm font-bold">
                What is {company}?
              </div>
              <AboutSection>
                <AboutContentSection noBottomMargin={doesNotHaveApiDescription}>
                  <AboutTitle>
                    <div className="flex items-center gap-2">
                      <IconInfoCircle size="1rem" className="text-slate-400" />
                      <div>About {company}</div>
                    </div>
                  </AboutTitle>
                  <p>{metaDescription}</p>
                </AboutContentSection>
                {!doesNotHaveApiDescription && (
                  <>
                    <AboutTitle>
                      <div className="flex items-center gap-2">
                        <IconApi size="1rem" className="text-slate-400" />
                        <div>About {company}'s API</div>
                      </div>
                    </AboutTitle>
                    <div className="[&_p]:mb-6">
                      <Description />
                    </div>
                  </>
                )}
              </AboutSection>
              <div className="text-slate-500 mb-1 text-sm font-bold">
                Integrating {company}'s {language} SDK
              </div>
              <AboutSection>
                <AboutContentSection>
                  <AboutTitle>
                    <div className="flex items-center gap-2 mb-[-12px]">
                      <IconPlayerPlay size="1rem" className="text-slate-300" />
                      <div>SDK Initialization</div>
                    </div>
                  </AboutTitle>
                  <div className="w-full">
                    <GettingStarted />
                  </div>
                </AboutContentSection>
                <AboutTitle>
                  <div className="flex items-center gap-2">
                    <IconCodeDots size="1rem" className="text-slate-300" />
                    <div>SDK Methods</div>
                  </div>
                </AboutTitle>
                <div className="space-y-4">
                  {methods.map(
                    ({
                      method,
                      url,
                      description,
                      httpMethod,
                      parameters,
                      responses,
                      typeScriptTag,
                      tag,
                    }) => {
                      return (
                        <SdkMethod
                          clientNameCamelCase={clientNameCamelCase}
                          key={`${method}-${url}`}
                          tag={tag}
                          method={method}
                          url={url}
                          description={description}
                          typeScriptTag={typeScriptTag}
                          httpMethod={httpMethod}
                          parameters={parameters}
                          responses={responses}
                          company={company}
                        />
                      )
                    },
                  )}
                </div>
              </AboutSection>
            </div>
            <Sidebar
              homepage={homepageWithHttpScheme}
              serviceName={serviceName}
              apiTitle={apiTitle}
              apiBaseUrl={apiBaseUrl}
              apiVersion={apiVersion}
              endpoints={endpoints}
              sdkMethods={sdkMethods}
              schemas={schemas}
              parameters={parameters}
              difficulty={difficulty}
              contactUrl={contactUrl}
              contactEmail={contactEmail}
              openApiRaw={openApiRaw}
            />
          </div>
        </BigSection>
      </div>
    </Layout>
  )
}

function AboutContentSection({
  children,
  noBottomMargin,
}: PropsWithChildren<{ noBottomMargin?: boolean }>) {
  return <div className={clsx({ 'mb-10': !noBottomMargin })}>{children}</div>
}

export function SdkMethod({
  method,
  url,
  httpMethod,
  description,
  parameters,
  tag,
  responses,
  clientNameCamelCase,
  typeScriptTag,
}: Method & {
  company: string
  clientNameCamelCase: string
}) {
  const [expanded, setExpanded] = useState(false)
  return (
    <div
      className={clsx(
        'text-slate-700 ring-1 ring-slate-200  rounded-md block w-full overflow-x-auto px-3 py-2 transition-all text-xs lg:text-sm bg-slate-100 hover:bg-slate-50',
        {
          'bg-slate-50': expanded,
        },
        {
          'scale-[1.01] shadow-xl': expanded,
        },
      )}
    >
      <button
        className="w-full text-left"
        onClick={() => {
          setExpanded(!expanded)
        }}
      >
        <div className="flex flex-col items-start">
          <div className="text-slate-500 font-mono font-semibold">{tag}</div>
          <h4
            className={clsx(
              'font-bold mb-1 text-base md:text-lg text-slate-800',
            )}
          >
            {<Markdown markdownText={description} />}
          </h4>
          <div className={clsx('mb-0 flex w-full justify-between')}>
            <span className="font-mono whitespace-nowrap">
              {typeScriptTag !== undefined
                ? `${clientNameCamelCase}.${typeScriptTag}.${method}()`
                : `${clientNameCamelCase}.${method}()`}
            </span>
            <IconChevronDown
              className={clsx('h-4 transition-transform shrink-0', {
                'rotate-180': expanded,
              })}
            />
          </div>
        </div>
      </button>
      <div
        className={clsx('text-left w-full', {
          'h-0 overflow-hidden': !expanded,
          'h-auto': expanded,
        })}
      >
        <SdkMethodSection
          Icon={IconAdjustments}
          header={parameters.length === 0 ? 'No Parameters' : 'Parameter'}
        >
          <div className="space-y-2">
            {parameters.map((parameter) => {
              return <SdkMethodParameter key={parameter.name} {...parameter} />
            })}
          </div>
        </SdkMethodSection>
        <SdkMethodSection
          header={responses.length === 0 ? 'No Responses' : 'Response'}
          Icon={IconCube}
        >
          <div className="space-y-2 w-full">
            {responses.map((response) => {
              return (
                <SdkMethodResponse key={response.statusCode} {...response} />
              )
            })}
          </div>
        </SdkMethodSection>
        <SdkMethodSection header="Endpoint" Icon={IconLink}>
          <div className="flex items-center gap-2 mb-3">
            <HttpMethodBadge httpMethod={httpMethod} />
            <div className={clsx('font-mono')}>{url}</div>
          </div>
        </SdkMethodSection>
      </div>
    </div>
  )
}

function SdkMethodResponse({
  statusCode,
  description,
}: {
  statusCode: string
  description?: string
}) {
  return (
    <div
      className={clsx('p-2 w-full border rounded-md', {
        'bg-blue-50 border-blue-100 text-blue-600': statusCode.startsWith('2'),
        'bg-red-50 border-red-100 text-red-600': !statusCode.startsWith('2'),
      })}
    >
      <span className="font-semibold">{statusCode}</span>
      {description && (
        <div className="mb-1">{<Markdown markdownText={description} />}</div>
      )}
    </div>
  )
}

function SdkMethodParameter({
  name,
  schema,
  required,
  description,
}: PropsWithChildren<Parameter>) {
  return (
    <div>
      <div className="flex flex-wrap gap-x-2 items-center">
        <SdkMethodParameterName>{name}</SdkMethodParameterName>
        <SdkMethodParameterSchema>{schema}</SdkMethodParameterSchema>
        {required && <SdkMethodParameterRequired />}
      </div>
      <div className="mt-1">{<Markdown markdownText={description} />}</div>
    </div>
  )
}

function SdkMethodParameterRequired() {
  return (
    <span className="font-mono text-red-600 p-1 rounded-md border-red-300 bg-red-100">
      required
    </span>
  )
}

function SdkMethodParameterName({ children }: PropsWithChildren<{}>) {
  return (
    <span
      className={clsx(
        'font-semibold p-1 rounded-md border font-mono bg-slate-200 text-slate-700 border-slate-400',
      )}
    >
      {children}
    </span>
  )
}

function SdkMethodParameterSchema({ children }: PropsWithChildren<{}>) {
  return <span className="font-mono">{children}</span>
}

function SdkMethodSection({
  header,
  children,
  Icon,
}: PropsWithChildren<{
  header: string
  Icon: (props: TablerIconsProps) => JSX.Element
}>) {
  return (
    <div className="flex w-full gap-2 mt-6">
      <Icon className={clsx('shrink-0 h-4 text-slate-500')} />
      <div className="flex flex-col grow items-start">
        <SdkMethodHeader className="font-semibold font-sans mb-2 uppercase">
          {header}
        </SdkMethodHeader>
        <div className="text-xs w-full">{children}</div>
      </div>
    </div>
  )
}

function SdkMethodHeader({
  children,
  className,
}: PropsWithChildren<{
  className?: string
}>) {
  return (
    <h5
      className={clsx(
        'font-bold whitespace-nowrap mb-1 text-xs font-mono text-slate-600',
        className,
      )}
    >
      {children}
    </h5>
  )
}

function BigSection({ children }: PropsWithChildren<{}>) {
  return (
    <div className="mx-4 lg:mx-auto lg:w-[960px] xl:w-[1152px]">{children}</div>
  )
}

function AboutSection({ children }: PropsWithChildren<{}>) {
  return (
    <div className="mb-10 ring-1 ring-slate-200 bg-white rounded-md shadow-md p-8">
      {children}
    </div>
  )
}

function AboutTitle({ children }: PropsWithChildren<{}>) {
  return <h3 className="text-slate-500 uppercase text-xs mb-2">{children}</h3>
}

function SignupForm({
  company,
  serviceName,
  language,
}: {
  company: string
  serviceName?: string
  language: string
}) {
  const {
    setEmail,
    signedUp,
    signedUpEmail,
    loading,
    handleSubmit,
    email,
  } = useSdkSignup({
    company,
    serviceName,
    language,
  })

  return (
    <form
      onSubmit={handleSubmit}
      id="signup"
      className="p-8 rounded-md bg-emerald-50 ring-1 ring-emerald-300 transition-all hover:scale-[1.01] hover:shadow-lg shadow-md mb-8"
    >
      <div className="flex flex-col">
        <h2
          className={clsx('text-lg lg:text-xl text-emerald-900 font-bold', {
            'mb-3': !signedUp,
          })}
        >
          {signedUp
            ? `Thanks for signing up for access to ${company}'s ${language} SDK 🎉!`
            : `Need a ${language} SDK for ${company}'s API?`}
        </h2>
        {signedUp ? (
          <>
            <p className="mb-4">{`Your email, ${signedUpEmail}, has been successfully registered for access to the ${language} SDK. We will notify you by email soon.`}</p>
            <p className="mb-0">
              For inquiries or support, please contact us at{' '}
              <a href="mailto:sdks@konfigthis.com">sdks@konfigthis.com</a>
            </p>
          </>
        ) : null}
        {signedUp ? null : (
          <input
            type="email"
            name="email"
            className="border rounded-md px-2 py-1 w-full mb-2"
            placeholder="Email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        )}
        {signedUp ? null : (
          <button
            type="submit"
            className="font-medium group flex gap-3 hover:gap-2 items-center transition-all bg-gradient-to-br text-white w-fit text-center px-3 py-2 from-emerald-600 to-emerald-800 rounded-md text-sm"
          >
            {loading ? (
              <LoadingIcon />
            ) : (
              <>
                <div>
                  Sign up for access to {company}'s {language} SDK
                </div>
                <IconPencil
                  size="1rem"
                  className="transition-all group-hover:text-emerald-50 text-emerald-300"
                />
              </>
            )}
          </button>
        )}
      </div>
    </form>
  )
}

function Sidebar({
  serviceName,
  apiTitle,
  apiBaseUrl,
  apiVersion,
  endpoints,
  sdkMethods,
  schemas,
  parameters,
  difficulty,
  contactUrl,
  contactEmail,
  openApiRaw,
  homepage,
}: {
  homepage: string
  serviceName: string
  apiTitle: string
  apiBaseUrl: string
  apiVersion: string
  endpoints: number
  sdkMethods: number
  schemas: number
  parameters: number
  difficulty: string
  contactUrl: string
  contactEmail: string
  openApiRaw?: string
}) {
  return (
    <div className="top-20 sticky w-full lg:w-fit">
      <div className="flex gap-1 items-center mb-1">
        <IconInfoCircle className="h-4 shrink-0 text-slate-400" />
        <div className="text-slate-500 text-sm font-bold">More Info</div>
      </div>
      <div className="bg-white ring-1 ring-slate-200 shadow-md p-8 lg:py-4 lg:px-6 rounded-md">
        {serviceName !== undefined ? (
          <SidebarSection>
            <SidebarSectionTitle>Service Name</SidebarSectionTitle>
            <SidebarSectionContent>{serviceName}</SidebarSectionContent>
          </SidebarSection>
        ) : null}
        <SidebarSection>
          <SidebarSectionTitle>API Title</SidebarSectionTitle>
          <SidebarSectionContent>{apiTitle}</SidebarSectionContent>
        </SidebarSection>
        {/*
        Commented because this would often be a broken external link which hurts SEO
        <SidebarSection>
          <SidebarSectionTitle>API Base URL</SidebarSectionTitle>
          <SidebarSectionContent className="whitespace-nowrap max-w-xs overflow-x-scroll">
            <a href={apiBaseUrl} target="_blank">
              {apiBaseUrl}
            </a>
          </SidebarSectionContent>
        </SidebarSection> */}
        {apiVersion && (
          <SidebarSection>
            <SidebarSectionTitle>API Version</SidebarSectionTitle>
            <SidebarSectionContent>{apiVersion}</SidebarSectionContent>
          </SidebarSection>
        )}
        <SidebarSection>
          <div className="flex justify-between">
            <div className="w-1/2">
              <SidebarSectionTitle>Endpoints</SidebarSectionTitle>
              <SidebarSectionContent>{endpoints}</SidebarSectionContent>
            </div>
            <div className="w-1/2">
              <SidebarSectionTitle>SDK Methods</SidebarSectionTitle>
              <SidebarSectionContent>{sdkMethods}</SidebarSectionContent>
            </div>
          </div>
        </SidebarSection>
        <SidebarSection noBorder>
          <div className="flex justify-between">
            <div className="w-1/2">
              <SidebarSectionTitle>Schemas</SidebarSectionTitle>
              <SidebarSectionContent>{schemas}</SidebarSectionContent>
            </div>
            <div className="w-1/2">
              <SidebarSectionTitle>Parameters</SidebarSectionTitle>
              <SidebarSectionContent>{parameters}</SidebarSectionContent>
            </div>
          </div>
        </SidebarSection>
        <SidebarSection>
          <SidebarSectionTitle>
            <div className="flex items-end gap-1">
              <div>API Difficulty</div>
              <a
                target="_blank"
                href="/difficulty-explanation"
                className="text-xs font-normal lowercase"
              >
                (What is this?)
              </a>
            </div>
          </SidebarSectionTitle>
          <SidebarSectionContent>
            <div className="">{difficulty}</div>
          </SidebarSectionContent>
        </SidebarSection>
        <SidebarSection>
          <SidebarSectionTitle>Homepage</SidebarSectionTitle>
          <SidebarSectionContent>
            <a href={homepage} target="_blank">
              {homepage.replace('https://', '').replace('http://', '')}
            </a>
          </SidebarSectionContent>
        </SidebarSection>
        {contactUrl && (
          <SidebarSection>
            <SidebarSectionTitle>Contact URL</SidebarSectionTitle>
            <SidebarSectionContent>
              <a href={contactUrl} target="_blank">
                {contactUrl.replace('https://', '').replace('http://', '')}
              </a>
            </SidebarSectionContent>
          </SidebarSection>
        )}
        {contactEmail && (
          <SidebarSection>
            <SidebarSectionTitle>Contact Email</SidebarSectionTitle>
            <SidebarSectionContent>
              <a href={`mailto:${contactEmail}`}>{contactEmail}</a>
            </SidebarSectionContent>
          </SidebarSection>
        )}
        {openApiRaw === undefined ? null : (
          <SidebarSection>
            <SidebarSectionTitle>OpenAPI Specification</SidebarSectionTitle>
            <SidebarSectionContent>
              <a
                href={openApiRaw}
                className="pr-4 mr-4 border-r-2"
                target="_blank"
              >
                Raw
              </a>
              <a
                href={`https://elements-demo.stoplight.io/?spec=${openApiRaw}`}
                target="_blank"
              >
                UI
              </a>
            </SidebarSectionContent>
          </SidebarSection>
        )}
      </div>
    </div>
  )
}

function SidebarSection({
  children,
  noBorder,
}: PropsWithChildren<{ noBorder?: boolean }>) {
  return <div className={clsx('py-2 lg:py-3 mb-1')}>{children}</div>
}

function SidebarSectionTitle({
  children,
  large,
}: PropsWithChildren<{ large?: boolean }>) {
  return (
    <h3
      className={clsx('mb-1 text-slate-500 uppercase text-xs', {
        'text-lg text-black': large,
      })}
    >
      {children}
    </h3>
  )
}

function SidebarSectionContent({
  children,
  className,
}: PropsWithChildren<{ className?: string }>) {
  return <div className={clsx('text font-semibold', className)}>{children}</div>
}

function Dot() {
  return <div className="h-[3px] w-[3px] bg-slate-300 rounded-full" />
}

export function HttpMethodBadge({ httpMethod }: { httpMethod: HttpMethods }) {
  const color = httpMethodColor(httpMethod)
  return (
    <div
      className={clsx('px-2 text-xs rounded-xl uppercase font-semibold', {
        'bg-green-100 text-green-700 border border-green-300':
          color === 'green',
        'bg-blue-100 text-blue-700 border border-blue-300': color === 'blue',
        'bg-red-100 text-red-700 border border-red-300': color === 'red',
        'bg-yellow-100 text-yellow-700 border border-yellow-300':
          color === 'yellow',
        'bg-slate-100 text-slate-700 border border-slate-300':
          color === 'slate',
      })}
    >
      {httpMethod}
    </div>
  )
}

function httpMethodColor(
  method: HttpMethods,
): 'green' | 'blue' | 'red' | 'yellow' | 'slate' {
  if (method === HttpMethodsEnum.GET) return 'green'
  if (method === HttpMethodsEnum.POST) return 'blue'
  if (method === HttpMethodsEnum.PUT) return 'blue'
  if (method === HttpMethodsEnum.DELETE) return 'red'
  if (method === HttpMethodsEnum.PATCH) return 'yellow'
  if (method === HttpMethodsEnum.OPTIONS) return 'yellow'
  if (method === HttpMethodsEnum.TRACE) return 'yellow'
  return 'slate'
}
